package user.view;

import static org.math.array.DoubleArray.increment;

import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.LinkedList;

import javax.swing.BorderFactory;
import javax.swing.JOptionPane;
import javax.swing.Timer;
import javax.swing.border.Border;
import javax.swing.text.JTextComponent;

import model.doe.AbstractDoe;
import model.doe.FocusatorKrest;
import model.doe.GaussHermiteModan;
import model.doe.GaussLaguerreModan;
import model.doe.RomeroDickeyGrating;
import model.util.FourerExecutor;
import model.util.FourerExecutor.DoeType;

import system.activity.MainListener;
import system.elements.ControlTextField;
import system.util.PlotBuilder;

public class RomeroGratingImpl extends Controls
{


	
	    private javax.swing.JComboBox beamType;
	    private javax.swing.JLabel beamsNumberLabel;
	    private ControlTextField beamsNumberText;
	    private javax.swing.JButton cancelButton;
	    private javax.swing.JLabel firstParamLabel;
	    private ControlTextField firstParamText;
	    private javax.swing.JLabel gStepLabel;
	    private ControlTextField gSteplText;
	    private javax.swing.JLabel eff;
	    private javax.swing.JButton okButton;
	    private javax.swing.JLabel radLabel;
	    private ControlTextField radText;
	    private javax.swing.JLabel secondParamLabel;
	    private ControlTextField secondParamText;
	    private javax.swing.JLabel neededEffLabel;
	    private ControlTextField neededEffText;
	    private javax.swing.JLabel maxIterationCountLabel;
	    private ControlTextField maxIterationCountText;
	    private javax.swing.JLabel startPhaseLabel;
	    private ControlTextField startPhaseText;
	    private javax.swing.JLabel endPhaseLabel;
	    private ControlTextField endPhaseText;
	    
	public RomeroGratingImpl(final MainListener listener)
	{
		this.listener = listener;
		this.setLayout(new java.awt.BorderLayout());

		init();
	}

	public RomeroGratingImpl(final MainListener listener, ArrayList<String> params)
	{
		this.listener = listener;
		this.setLayout(new java.awt.BorderLayout());
		initFromHistory(params);
	}
	
	@Override
	protected LinkedList<JTextComponent> elementsQueue()
	{
		LinkedList<JTextComponent> result = new LinkedList<JTextComponent>();
		result.add(beamsNumberText);
		result.add(neededEffText);
		result.add(maxIterationCountText);
		result.add(gSteplText);
		result.add(startPhaseText);
		result.add(endPhaseText);
		result.add(firstParamText);
		result.add(secondParamText);
		result.add(radText);
		return result;
	}
	
	@Override
	protected void init()
	{
		beamsNumberLabel = new javax.swing.JLabel();
        beamsNumberText = new ControlTextField();
        neededEffText = new ControlTextField();
        neededEffLabel = new javax.swing.JLabel();
        maxIterationCountText = new ControlTextField();
        maxIterationCountLabel = new javax.swing.JLabel();
        gSteplText = new ControlTextField();
        gStepLabel = new javax.swing.JLabel();
        radText = new ControlTextField();
        radLabel = new javax.swing.JLabel();
        okButton = new javax.swing.JButton();
        cancelButton = new javax.swing.JButton();
        firstParamLabel = new javax.swing.JLabel();
        firstParamText = new ControlTextField();
        secondParamLabel = new javax.swing.JLabel();
        secondParamText = new ControlTextField();
        beamType = new javax.swing.JComboBox();
        eff = new javax.swing.JLabel();
        startPhaseLabel = new javax.swing.JLabel();
        endPhaseLabel = new javax.swing.JLabel();
        startPhaseText = new ControlTextField();
        endPhaseText = new ControlTextField();
        

		setName("Form"); // NOI18N

		beamsNumberLabel.setText("Количество пучков"); // NOI18N
        beamsNumberText.setText("3"); // NOI18N
        neededEffText.setText("0.98"); // NOI18N
        neededEffLabel.setText("Желаемая эффективность"); // NOI18N
        maxIterationCountText.setText("5"); // NOI18N
        maxIterationCountLabel.setText("Количество попыток"); // NOI18N
        gSteplText.setText("1024"); // NOI18N
        gStepLabel.setText("Количество отсчетов"); // NOI18N
        radText.setText("25"); // NOI18N
        radLabel.setText("Радиус пучка"); // NOI18N
        okButton.setText("Рассчитать"); // NOI18N
        cancelButton.setText("Закрыть"); // NOI18N
        firstParamLabel.setText("Параметр моды №1"); // NOI18N
        firstParamText.setText("0"); // NOI18N
        secondParamLabel.setText("Параметр моды №2"); // NOI18N
        secondParamText.setText("0"); // NOI18N
        beamType.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Пучок Эрмита-Гаусса", "Пучок Лагерра-Гаусса" }));
        startPhaseLabel.setText("Начало диапазона фазовой функции"); // NOI18N
        endPhaseLabel.setText("Конец диапазона фазовой функции"); // NOI18N
        startPhaseText.setText("-200"); // NOI18N
        endPhaseText.setText("200"); // NOI18N
        
        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                        .addComponent(okButton)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(cancelButton))
                    .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addComponent(endPhaseLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 148, Short.MAX_VALUE)
                            .addComponent(startPhaseLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 148, Short.MAX_VALUE)
                            .addComponent(beamsNumberLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 148, Short.MAX_VALUE)
                            .addComponent(neededEffLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 148, Short.MAX_VALUE)
                            .addComponent(maxIterationCountLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 148, Short.MAX_VALUE)
                            .addComponent(gStepLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 148, Short.MAX_VALUE))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addComponent(endPhaseText, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 113, Short.MAX_VALUE)
                            .addComponent(gSteplText, javax.swing.GroupLayout.DEFAULT_SIZE, 113, Short.MAX_VALUE)
                            .addComponent(maxIterationCountText, javax.swing.GroupLayout.DEFAULT_SIZE, 113, Short.MAX_VALUE)
                            .addComponent(neededEffText, javax.swing.GroupLayout.DEFAULT_SIZE, 113, Short.MAX_VALUE)
                            .addComponent(beamsNumberText, javax.swing.GroupLayout.DEFAULT_SIZE, 113, Short.MAX_VALUE)
                            .addComponent(startPhaseText, javax.swing.GroupLayout.DEFAULT_SIZE, 113, Short.MAX_VALUE)))
                    .addComponent(beamType, javax.swing.GroupLayout.Alignment.TRAILING, 0, 265, Short.MAX_VALUE)
                    .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addComponent(radLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 148, Short.MAX_VALUE)
                            .addComponent(firstParamLabel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 148, Short.MAX_VALUE)
                            .addComponent(secondParamLabel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 148, Short.MAX_VALUE))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addComponent(radText, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 113, Short.MAX_VALUE)
                            .addComponent(firstParamText, javax.swing.GroupLayout.DEFAULT_SIZE, 113, Short.MAX_VALUE)
                            .addComponent(secondParamText, javax.swing.GroupLayout.DEFAULT_SIZE, 113, Short.MAX_VALUE)))
                    .addComponent(eff))
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(beamsNumberLabel)
                    .addComponent(beamsNumberText, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addGap(18, 18, 18)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(neededEffLabel)
                    .addComponent(neededEffText, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addGap(18, 18, 18)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(maxIterationCountLabel)
                    .addComponent(maxIterationCountText, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addGap(18, 18, 18)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(gStepLabel)
                    .addComponent(gSteplText, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addGap(20, 20, 20)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(startPhaseLabel)
                    .addComponent(startPhaseText, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addGap(18, 18, 18)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(endPhaseLabel)
                    .addComponent(endPhaseText, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addGap(18, 18, 18)
                .addComponent(beamType, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(radLabel)
                    .addComponent(radText, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addGap(18, 18, 18)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(firstParamLabel)
                    .addComponent(firstParamText, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addGap(18, 18, 18)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(secondParamText, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(secondParamLabel))
                .addGap(18, 18, 18)
                .addComponent(eff)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 16, Short.MAX_VALUE)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(okButton)
                    .addComponent(cancelButton))
                .addContainerGap())
        );
        
		okButton.addMouseListener(new java.awt.event.MouseAdapter()
		{
			public void mouseClicked(java.awt.event.MouseEvent evt)
			{
				try {
					if((Integer.parseInt(beamsNumberText.getText()))%2==0)
					{
						throw new IllegalArgumentException();
					}
					okButton.setEnabled(false);
					listener.clearImagePanel();
					listener.setLoadStatus();
					java.awt.event.ActionListener actionListener = new java.awt.event.ActionListener()
					{
						public void actionPerformed(java.awt.event.ActionEvent actionEvent)
						{
							try {
								AbstractDoe modan;
								if(beamType.getSelectedIndex()==0)
								{
									modan = new GaussHermiteModan(Double.parseDouble(gSteplText.getText()),Double.parseDouble(gSteplText.getText()),1,Double.parseDouble(radText.getText()),Integer.parseInt(firstParamText.getText()),Integer.parseInt(secondParamText.getText()));
								}
								else
								{
									modan = new GaussLaguerreModan(Double.parseDouble(gSteplText.getText()),Double.parseDouble(gSteplText.getText()),1,Double.parseDouble(radText.getText()),Integer.parseInt(firstParamText.getText()),Integer.parseInt(secondParamText.getText()));	
								}
								final RomeroDickeyGrating grating= new RomeroDickeyGrating((Integer.parseInt(beamsNumberText.getText())-1)/2,  Integer.parseInt(gSteplText.getText()), Double.parseDouble(startPhaseText.getText()), Double.parseDouble(endPhaseText.getText()),modan);
								grating.buildGratinfWithOptimalParams(Double.parseDouble(neededEffText.getText()), Integer.parseInt(maxIterationCountText.getText()));
								ArrayList<BufferedImage> afterFourerImages;
								FourerExecutor fourer = new FourerExecutor();
								afterFourerImages =fourer.fft(grating, DoeType.PHASE_MODAN_AMPLITUDE);
									listener.addImagePanel(afterFourerImages.get(0), "Распределение амплитуды после преобразования фурье");
									String effString = (grating.getEff()*100)+"";
									eff.setText("Эффективность делителя  -  " + effString.substring(0, 6) +" %");
									double[][] z = fourer.getResultInt();
									double[] x = increment(0d, 1d, z[0].length);
									double[] y = increment(0d, 1d, z.length);
									String plotDescription = "Распределение интенсивонсти после преобразования фурье";
									listener.addFastPlotPanel(PlotBuilder.buildFast3DPlot(x, y, z, plotDescription), plotDescription+" - 3D график");
									listener.addPlotPanel(PlotBuilder.build2DPlot(x, z[z.length/2], plotDescription), plotDescription+" - график сечения");
									listener.addPlotPanel(PlotBuilder.build2DPlot(grating.getxPhase(), grating.getPhase(), "Профиль делителя пучка"), "Профиль делителя пучка");
									onResize();
									listener.needRepaint();
								listener.removeLoadStatus();
								okButton.setEnabled(true);
							} catch (OutOfMemoryError ex) {
								listener.removeLoadStatus();
								okButton.setEnabled(true);
								listener.showErrorMessage("Переполнение памяти");
							}
						}
					};
					Timer timer = new Timer(500, actionListener);
					timer.setRepeats(false);
					timer.start();
				} catch (NumberFormatException ex) {
					listener.showErrorMessage("Ошибка формата входных данных");
					listener.removeLoadStatus();
					okButton.setEnabled(true);
				} catch (IllegalArgumentException ex) {
					okButton.setEnabled(true);
					listener.showErrorMessage("Неверные входные данные");
				}
			}
		});
		cancelButton.addMouseListener(new java.awt.event.MouseAdapter()
		{
			public void mouseClicked(java.awt.event.MouseEvent evt)
			{
				listener.removeLeftPanel();
				onResize();
				listener.needRepaint();
			}
		});
		Border border = BorderFactory.createEtchedBorder(Color.white, new Color(178, 178, 178));
		this.setBorder(border);
		listener.addPanel(this);
		this.show();
	}

	void onResize()
	{
		this.show();
	}

	@Override
	public void setListener(MainListener listener)
	{
		this.listener = listener;
	}

	@Override
	public Collection<String> getControlsValues()
	{
		Date date = new Date();
		Collection<String> result = new ArrayList<String>();
		/*result.add("                                                                                 " + date.getHours() + ":" + date.getMinutes() + ":"
				+ date.getSeconds() + "   " + date.getDate() + "." + (date.getMonth() + 1) + "." + (date.getYear() + 1900));
		result.add("Фокусатор в перекрестие");
		result.add("Введенные параметры:");
		result.add(apertureRadiusLabel.getText() + " = " + apertureRadiusText.getText());
		result.add(focalLengtnLabel.getText() + " = " + focalLengthText.getText());
		result.add(crossSizeLabel.getText() + " = " + crossSizeText.getText());
		result.add(wlLabel.getText() + " = " + wlText.getText());
		result.add(angelLabel.getText() + " = " + angelText.getText());
		result.add(maxIterationCountLabel.getText() + " = " + stepText.getText());
		result.add(withLens.isSelected() ? "Расчет проводился с линзой" : "Расчет проводился без линзы");
		result.add("");*/
		return result;
	}
	@Override
	String getClassName()
	{
		return this.getClass().getCanonicalName();
	}
}
